
package com.joysuch.wwyt.mh.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.zlg.common.util.CollectionUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.google.common.collect.Lists;
import com.joysuch.wwyt.common.constant.Constant;
import com.joysuch.wwyt.core.bean.SimpleStringBean;
import com.joysuch.wwyt.core.common.util.PageDataUtils;
import com.joysuch.wwyt.core.enums.Status;
import com.joysuch.wwyt.core.exception.ApiBusinessException;
import com.joysuch.wwyt.core.service.BaseImageRepositoryService;
import com.joysuch.wwyt.core.service.BizCodeGeneratorFacade;
import com.joysuch.wwyt.core.support.Context;
import com.joysuch.wwyt.mh.bean.MhMonitoringTypeAddBean;
import com.joysuch.wwyt.mh.entity.MhMonitoringPoint;
import com.joysuch.wwyt.mh.entity.MhMonitoringType;
import com.joysuch.wwyt.mh.entity.dsl.QMhMonitoringType;
import com.joysuch.wwyt.mh.repository.MhMonitoringPointDao;
import com.joysuch.wwyt.mh.repository.MhMonitoringTypeDao;
import com.joysuch.wwyt.mh.service.MhMonitoringTypeService;
import com.joysuch.wwyt.patrol.entity.bean.SimpleListDataType;
import com.joysuch.wwyt.patrol.mapper.PatrolCheckItemMapper;
import com.joysuch.wwyt.workflow.service.WorkFlowProcessService;
import com.querydsl.core.types.ExpressionUtils;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.BooleanExpression;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import javax.persistence.Tuple;
import javax.transaction.Transactional;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional
@Slf4j
public class MhMonitoringTypeServiceImpl implements MhMonitoringTypeService {

    /**
     *
     */
    @Autowired
    private MhMonitoringTypeDao mhMonitoringTypeDao;
    @Autowired
    private MhMonitoringPointDao mhMonitoringPointDao;
    @Autowired
    private BaseImageRepositoryService imageRepositoryService;
    @Autowired
    private BizCodeGeneratorFacade bizCodeGeneratorFacade;
    @Autowired
    private WorkFlowProcessService workFlowProcessService;
    @Autowired
    private PatrolCheckItemMapper patrolCheckItemMapper;

    @Override
    public List<MhMonitoringType> list(Long categoryId) {
        List<MhMonitoringType> types = new ArrayList<>();
        Iterable<MhMonitoringType> it = mhMonitoringTypeDao.findAll();
        List<MhMonitoringType> itList = Lists.newArrayList(it);
        if (CollectionUtils.isNotEmpty(itList)) {
            if (categoryId == null) {
                types = itList;
            } else {
                for (MhMonitoringType m : it) {
                    if (m.getCategoryId().equals(categoryId)) {
                        types.add(m);
                    }
                }
            }
        }
        return types;
    }

    /**
     * 增加监测点类型
     *
     * @param bean
     * @return
     */
    @Override
    public MhMonitoringType addType(MhMonitoringTypeAddBean bean) {
        if (bean.getUnit() != null) {
            List<MhMonitoringType> mList = mhMonitoringTypeDao.findByNameAndUnit(bean.getName(), bean.getUnit());
            if (mList != null && mList.size() > 0) {
                throw new IllegalArgumentException("监测类型已存在");
            }
        } else {
            List<MhMonitoringType> mList = mhMonitoringTypeDao.findByName(bean.getName());
            if (mList != null && mList.size() > 0) {
                throw new IllegalArgumentException("监测类型已存在");
            }
        }
        MhMonitoringType type = new MhMonitoringType();
        MhMonitoringType saveType = mhMonitoringTypeDao.save(this.entityToBean(type, bean));
        if (bean.getCategoryId() != null && bean.getCategoryId().equals(1L)) {
            workFlowProcessService.saveConfigFromMhPointType(saveType);
        }
        return saveType;
    }

    /**
     * 修改监测点类型
     *
     * @param bean
     * @return
     */
    @Override
    public MhMonitoringType updateType(MhMonitoringTypeAddBean bean) {
        if (bean.getId() == null) {
            throw new IllegalArgumentException("监测点类型不存在");
        }
        Optional<MhMonitoringType> ot = mhMonitoringTypeDao.findById(bean.getId());
        if (!ot.isPresent()) {
            throw new IllegalArgumentException("监测点类型不存在");
        }
        if (bean.getUnit() != null) {
            List<MhMonitoringType> mList = mhMonitoringTypeDao.findByNameAndUnitAndIdNotEq(bean.getName(), bean.getUnit(), bean.getId());
            if (mList != null && mList.size() > 0) {
                throw new IllegalArgumentException("监测类型已存在");
            }
        } else {
            List<MhMonitoringType> mList = mhMonitoringTypeDao.findByNameAndIdNotEq(bean.getName(), bean.getId());
            if (mList != null && mList.size() > 0) {
                throw new IllegalArgumentException("监测类型已存在");
            }
        }
        MhMonitoringType mhMonitoringType = ot.get();
        mhMonitoringType = this.entityToBean(mhMonitoringType, bean);
        mhMonitoringType.setId(bean.getId());
        MhMonitoringType saveType = mhMonitoringTypeDao.save(mhMonitoringType);
        //修改大屏专栏配置
        if (bean.getCategoryId() != null && bean.getCategoryId().equals(1L)) {
            workFlowProcessService.saveConfigFromMhPointType(saveType);
        }
        return saveType;
    }

    private MhMonitoringType entityToBean(MhMonitoringType type, MhMonitoringTypeAddBean bean) {
        type.setName(bean.getName());
        type.setUnit(bean.getUnit());
        type.setCategoryId(bean.getCategoryId());
        type.setDefaultType(bean.getDefaultType());
        if (CollectionUtils.isNotEmpty(bean.getUnits())) {
            Map<String, String> map = new LinkedHashMap<>();
            for (SimpleStringBean u : bean.getUnits()) {
                if (map.get(u.getCode()) != null) {
                    throw new IllegalArgumentException("读取值不能重复");
                }
                map.put(u.getCode(), u.getName());
            }
            type.setUnits(JSON.toJSONString(map));
        } else {
            type.setUnits(null);
        }
        type.setNumber(0);
        if (bean.getImageBean() != null) {
            type.setImageId(bean.getImageBean().getId());
        }
        if (type.getCode() == null) {
            type.setCode(bizCodeGeneratorFacade.jiancedianleixing());
        }
        return type;
    }

    /**
     * 删除监测点类型
     *
     * @param id
     */
    @Override
    public void deleteType(Long id) throws ApiBusinessException {
        MhMonitoringType type = mhMonitoringTypeDao.findById(id).orElseThrow(() -> new IllegalArgumentException("监测点类型不存在"));
        int count = mhMonitoringPointDao.countByMonitoringTypeIdAndShowState(id);
        if (count > 0 ) {
            throw new IllegalArgumentException("请先删除该类型下的监测点");
        }
        //判断该类型有没有被检查项目(检查点)使用
        List<String> errMes = patrolCheckItemMapper.getPointByTypeId(id,Context.getCurrentTenantId(),Context.getCurrentOrgCode());
        if (CollectionUtil.isNotEmpty(errMes)){
            String pointNames = errMes.stream().map(Object::toString).collect(Collectors.joining(Constant.SPLIT_COMMA));
            throw new ApiBusinessException(Status.DATA_TYPE_BIND_POINT,pointNames);
        }
        mhMonitoringTypeDao.deleteById(id);
        //环境监测点类型删除 同步到大屏
        if (type.getCategoryId() != null && type.getCategoryId().equals(1L)) {
            workFlowProcessService.deleteEnvironmentPointConfig(type);
        }
    }

    /**
     * 分页查看监测点类型
     *
     * @param page
     * @param condition
     * @return
     */
    @Override
    public Page<MhMonitoringTypeAddBean> pageType(Pageable page, MhMonitoringTypeAddBean.Search condition) {

        Predicate predicate = prepareListSearchConditionExerciseRecord(condition);
        page = PageDataUtils.addOrderByDesc(page, "id");
        Page<MhMonitoringType> data = predicate == null ? mhMonitoringTypeDao.findAll(page) : mhMonitoringTypeDao.findAll(predicate, page);
        return PageDataUtils.convertPageData(data, new PageDataUtils.PageDataConvert<MhMonitoringTypeAddBean, MhMonitoringType>() {
            @Override
            public MhMonitoringTypeAddBean convert(MhMonitoringType baseConfig) {
                MhMonitoringTypeAddBean bean = new MhMonitoringTypeAddBean();
                BeanUtils.copyProperties(baseConfig, bean, "unit");
                //兼容监测点类型无number的旧数据,显示真实数据
                if (baseConfig.getId() != null) {
                    Optional<MhMonitoringType> omt = mhMonitoringTypeDao.findById(baseConfig.getId());
                    if (omt.isPresent()) {
                        List<MhMonitoringPoint> pList = mhMonitoringPointDao.findByMhMonitoringType(omt.get().getId());
                        if (pList != null && pList.size() > 0) {
                            bean.setNumber(pList.size());
                        } else {
                            bean.setNumber(0);
                        }
                    }
                }
                if (baseConfig.getImageId() != null) {
                    bean.setImageBean(imageRepositoryService.findBeanById(baseConfig.getImageId()));
                }
                bean.setUnits(getPointTypeUnits(baseConfig));
                //旧数据兼容
                if (StringUtils.isBlank(baseConfig.getDefaultType())) {
                    bean.setDefaultType("N");
                }
                bean.setUnit(baseConfig.getUnit());
                return bean;
            }
        });
    }

    @Override
    public List<SimpleStringBean> getPointTypeUnits(MhMonitoringType baseConfig) {
        if (StringUtils.isNotBlank(baseConfig.getDefaultType()) && baseConfig.getDefaultType().equals("Y") && StringUtils.isNotBlank(baseConfig.getUnits())) {
            List<SimpleStringBean> units = new ArrayList<>();
            Map<String, String> map = JSON.parseObject(baseConfig.getUnits(), LinkedHashMap.class, Feature.OrderedField);
            for (Map.Entry<String, String> entry : map.entrySet()) {
                SimpleStringBean stringBean = new SimpleStringBean();
                stringBean.setCode(entry.getKey());
                stringBean.setName(entry.getValue());
                units.add(stringBean);
            }
            return units;
        } else {
            return null;
        }
    }

    private Predicate prepareListSearchConditionExerciseRecord(MhMonitoringTypeAddBean.Search condition) {
        Predicate p = null;
        QMhMonitoringType q = QMhMonitoringType.mhMonitoringType;
        if (condition.getNameOrUnit() != null) {
            p = ExpressionUtils.and(p, ExpressionUtils.or(q.name.contains(condition.getNameOrUnit()),
                    q.unit.contains(condition.getNameOrUnit())));
        }
        p = condition.getCategoryId() == null ? p
                : ExpressionUtils.and(p, q.categoryId.eq(condition.getCategoryId()));
        return p;
    }

    @Override
    public List<SimpleListDataType> getSimpleList() {
        Long tenentId = Context.getCurrentTenantId();
        String orgCode = Context.getCurrentOrgCode();
        List<Tuple> simpleList = mhMonitoringTypeDao.getSimpleList(tenentId, orgCode);
        List<SimpleListDataType> simpleListDataTypeList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(simpleList)){
            
            for (Tuple tuple : simpleList) {
                SimpleListDataType dataType = new SimpleListDataType();
                Object id = tuple.get("id");
                Object dataTypeName = tuple.get("dataTypeName");
                dataType.setId(Long.parseLong(id.toString()));
                dataType.setDataTypeName((String)dataTypeName);
                simpleListDataTypeList.add(dataType);
            }
        }
        return simpleListDataTypeList;
    }
}
